use core::fmt;
use std::{ops::Deref, sync::Arc};
use anyhow::Context;
use axum::{Router, middleware::from_fn_with_state, routing::{get, post}};
use config::AppConfig;
use chat_core::{User, middlewares::{TokenVerify,auth::verify_token, set_layer}, utils::jwt::{DecodingKey, EncodingKey}};

use sqlx::PgPool;
use tokio::fs;
use tower_http::cors::{Any, CorsLayer};

use crate::{error::AppError, handlers::{auth::{signin_handler, signup_handler}, chat::{create_chat_handler, list_chat_handler}, messages::{list_message_handler, send_message_handler}, workspace::list_chat_users_handler}};

pub mod config; 
pub mod error;
pub mod models;
pub mod handlers;
pub mod middlewares;
pub use models::*;
use middlewares::chat::verify_chat;






#[derive(Debug,Clone)]
pub struct AppState {
    inner: Arc<AppStateInner>,
}


pub struct AppStateInner {
    pub(crate) config: AppConfig,
    pub(crate) dk: DecodingKey,
    pub(crate) ek: EncodingKey,
    pub(crate) pool: PgPool,
}


pub async fn get_router(state: AppState) ->Result<Router,AppError> {

    let chat = Router::new()
    .route("/:id", post(send_message_handler))
    .route("/:id/messages",get(list_message_handler))
    .layer(from_fn_with_state(state.clone(),verify_chat))
    .route("/",post(create_chat_handler).get(list_chat_handler));


    let cors = CorsLayer::new()
    .allow_origin(Any)
    .allow_methods(Any) 
    .allow_headers(Any);

    //create routes here with set middlewares
    let api = Router::new()
    .route("/users",get(list_chat_users_handler))
    .nest("/chats", chat)
    .layer(from_fn_with_state(state.clone(),verify_token::<AppState>))
    .route("/signin",post(signin_handler))
    .route("/signup", post(signup_handler))
    .layer(cors);

    let app = Router::new()
    .nest("/api", api)
    .with_state(state);

    Ok(set_layer(app))
}

impl Deref for AppState {
    type Target = AppStateInner;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl TokenVerify for AppState {
    type Error = AppError;


    fn verify(&self,token: &str) -> Result<User,Self::Error> {
        //verify token here
        Ok(self.dk.verify(token)?)
    }
    
}



impl AppState {
    pub async fn try_new(config: AppConfig) ->Result<Self,AppError>{
        //initialize db pool,dk,ek here
        fs::create_dir_all(&config.server.base_dir)
        .await
        .context("create base_dir failed")?;
    let dk = DecodingKey::load(&config.auth.pk).context("load decoding key failed")?;
    let ek = EncodingKey::load(&config.auth.sk).context("load encoding key failed")?;
    let pool = PgPool::connect(&config.server.db_url)
    .await
    .context("connect to db failed")?;
Ok(Self {
            inner: Arc::new(AppStateInner {
                config,
                dk,
                ek,
                pool,
            }),
        })
    }
}

impl fmt::Debug for AppStateInner {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("AppStateInner")
            .field("config", &self.config)
            .finish()
    }
}